<?php defined('SYSPATH') or die('No direct script access.');

class Model_Product extends Model_Filter
{ 
    const PRODUCTS_PER_PAGE = 60;
    protected $_reload_on_wakeup = false;
    
    public static function get_available_prices()
    {
        return array(
            array('from' => null,  'to' => 500),
            array('from' => 500,   'to' => 1000),
            array('from' => 1000,  'to' => 1500),
            array('from' => 1500,  'to' => 2000),
            array('from' => 2000,  'to' => 3000),
            array('from' => 3000,  'to' => 4000),
            array('from' => 4000,  'to' => 5000),
            array('from' => 5000,  'to' => 7000),
            array('from' => 7000,  'to' => 10000),
            array('from' => 10000, 'to' => 15000),
            array('from' => 15000, 'to' => null),
        );
    }
    
    public static function get_prices()
    {
        return self::get_available_prices();
    }
    
    public function get_products_for_main()
    {
        if ($products = Cache::instance()->get('main_products')) {
            return $products;
        }
        
        $products = array();
        $categories = ORM::factory('category')->get_main_categories();
        foreach ($categories as $category) {
			$ids = array();
			if ($category->childs) {
				$ids   = explode(',', $category->childs);
			}
            $ids[] = $category->id;
            $top = $this->_get_products_query()
                        ->where('category_id', 'IN', $ids)
                        ->order_by('sort', 'DESC')
                        ->limit(6)
                        ->find_all()
                        ->as_array(); 
            $products[$category->id] = $top;    
        }
        
        Cache::instance()->set('main_products', $products);
        return $products;    
    }
    
    public function get_products($category = null, $tag = null, $brands = null, $shops = null, $price = null, $page = null, $count = false)
    {   
        $ids = array();
        $category_id = self::_get_category_id($category, $ids);
        
        $tag_id      = self::_get_tag_id($tag);
        
        $brand_ids   = self::_get_brand_ids($brands);
        
        $shop_ids    = self::_get_shop_ids($shops);
        
        $from_price  = self::_get_from_price($price);
        $to_price    = self::_get_to_price($price);
        
        if ($products = Cache::instance()->get('products_'.$category_id.'_'.$tag_id.'_'.$brands.'_'.$shops.'_'.$from_price.'_'.$to_price.'_'.$page.'_'.$count)) {
            return $products;
        }
         
        $query = $this->_get_products_query(); 
        
        if (is_array($ids) && count($ids) > 0) {
            $query->where('category_id', 'IN', $ids);
        }
        
        if ($tag_id) {
            $query->join('product_tags', 'LEFT')
                    ->on('product_tags.product_id', '=', 'product.id')
                    ->where('product_tags.tag_id', '=', $tag_id);    
        }
        
        if (is_array($brand_ids) && count($brand_ids) > 0) {
            $query->where('brand_id', 'IN', $brand_ids);    
        }
        
        if (is_array($shop_ids) && count($shop_ids) > 0) {
            $query->where('shop_id', 'IN', $shop_ids);    
        }
        
        if ($from_price) {
            $query->where('price', '>=', $from_price);    
        }
        if ($to_price) {
            $query->where('price', '<=', $to_price); 
        }
        
        if ($tag_id) {
            $query->order_by('product_tags.sort', 'DESC');    
        } else {
            $query->order_by('product.sort', 'DESC');   
        }
        
        if ($count) {
            $result = $query->count_all();
            Cache::instance()->set('products_'.$category_id.'_'.$tag_id.'_'.$brands.'_'.$shops.'_'.$from_price.'_'.$to_price.'_'.$page.'_'.$count, $result);
            return $result;
        }        
            
        if ($page) {
            $_count = self::get_products_per_page();
            $offset = ($page - 1) * $_count;
            $query->offset($offset)->limit($_count);    
        }
        
        $products = $query->find_all()->as_array(); 
        if ($tag_id && count($products) < self::get_products_per_page() && $page == 1) {
            $add_products = ORM::factory('product')->get_products($category, null, $brands, $shops, array('from' => $from_price, 'to' => $to_price), 1);   
            $products = array_merge($products, $add_products);
        } 
        Cache::instance()->set('products_'.$category_id.'_'.$tag_id.'_'.$brands.'_'.$shops.'_'.$from_price.'_'.$to_price.'_'.$page.'_'.$count, $products); 
        return $products;
    } 
    
    public function get_related_products($limit = 24)
    {
        $products = $this->_get_products_query()
            ->where('id', '>', $this->id)
            ->where('category_id', '=', $this->category_id)
            //->order_by('id', 'ASC')
            ->limit($limit)
            ->find_all()
            ->as_array();
            
        if (count($products) < $limit) {
            $limit = $limit - count($products);
            $new_products = $this->_get_products_query()
                ->where('id', '<', $this->id)
                ->where('category_id', '=', $this->category_id)
                //->order_by('id', 'ASC')
                ->limit($limit)
                ->find_all()
                ->as_array();
            $products = array_merge($products, $new_products);    
        }
        return $products;
        
        /*$data = DB::query(Database::SELECT, 
                        "SELECT MIN(id) AS min, MAX(id) AS max
                         FROM products
                         WHERE category_id = {$this->category_id}")->execute()->as_array();
        $data = $data[0];
        $ids = array();
        
        for ($i = 1; $i < $limit*20; $i++) {
            mt_srand($this->id + $i);      
            $rand = mt_rand($data['min'], $data['max']);
            $ids[$rand] = $rand;   
        }
        
        $products = array();    
        $_products = $this->_get_products_query()
            ->where('id', 'IN', $ids)
            ->where('category_id', '=', $this->category_id)
            ->where('id', '!=', $this->id)
            ->limit($limit)
            ->find_all()
            ->as_array();
        foreach ($_products as $product) {
            mt_srand($product->id);      
            $rand = mt_rand(1, 10000);
            $products[$rand] = $product;   
        }
        ksort($products);
        return $products;  */
    } 
    
    public function get_differentcolor_products()
    {  
        $products = array();
        if ($this->shop_id != 4102) {  // пока есть только вайлды
            return $products;    
        }
        
        $ids = array();
        $_ids = DB::select('product_id2')
                    ->from('product_differentcolors')
                    ->where('product_id', '=', $this->id)
                    ->execute()
                    ->as_array();
        foreach ($_ids as $item) {
            $ids[] = $item['product_id2'];   
        }
                    
        $products = array();
        if (count($ids)) {
            $products = $this->_get_products_query()
                ->where('id', 'IN', $ids)
                ->find_all()
                ->as_array();        
        }
        return $products;
    }  
    
    public static function get_products_per_page()
    {
        return self::PRODUCTS_PER_PAGE;
    }
    
    public function get_product_data()
    {
        $data = DB::select()
                    ->from('product_data')
                    ->where('product_id', '=', $this->id)
                    ->execute()
                    ->as_array();
        if (isset($data[0])) {
            $data[0]['description'] = str_replace(array('&lt;', '&gt;'), array('<', '>'), $data[0]['description']);
            return $data[0];
        }
        return array(
            'description'  => null,
            'images'       => null,
            'params'       => null,
            'clean_params' => null,
            'invisible_params' => null,
        );
    }
    
    public function get_products_data($products)
    {
        // TODO key-value хранилище для этих данных
        $ids = array();
        foreach ($products as $product) {
            $ids[] = $product->id;   
        }
        
        $data = array();
        if (count($ids)) {
            $tmp_data = DB::select()
                    ->from('product_data')
                    ->where('product_id', 'IN', $ids)
                    ->execute()
                    ->as_array();
            
            /*$tmp_data = DB::select()
                    ->from('product_data')
                    ->where('product_id', '=', $ids[0]);
            for ($i = 1; $i < count($ids); $i++) {
                $subquery = DB::select()
                                ->from('product_data')
                                ->where('product_id', '=', $ids[$i]);
                $tmp_data->union($subquery);    
            }
            
            $tmp_data = $tmp_data->execute()
                    ->as_array();   */
                    
            foreach ($tmp_data as $item) {  
                $item['description'] = str_replace(array('&lt;', '&gt;'), array('<', '>'), $item['description']); 
                $data[$item['product_id']] = $item;    
            }   
        }
        return $data;
    }
    
    public function extract_specs($product_data = null)
    {
        if (!$product_data) {
            $product_data = $this->get_product_data();
        }
        
        $specs     = array();
        /*if (!in_array($this->shop_id, array(1001, ))) {      
            $tmp_specs = explode("\n", $this->description);
            foreach ($tmp_specs as $item) {
                try {
                    list($name, $value) = explode(':', $item);
                    $name  = str_replace('- ', '', trim($name));
                    $value = trim($value);
                    $specs[$name] = $value;
                } catch (Exception $e) {
                    
                }    
            }
        }*/
                                      
        if ($product_data['params']) {
            foreach (json_decode($product_data['params'], true) as $name => $value) {
                $specs[$name] = $value;    
            }
        }  
        return $specs;
    }
    
    public function get_name($category = null, $tag = null)
    {
        $names = array();
        // сплитим все names
        if ($this->names) {
            $names = explode('||', $this->names);  
            /*foreach ($_names as $name) {
                $names[$name] = $name;   
            }  */
        }
        
        // добавляем название категории, если надо
        /*if ($category) {
            $name = mb_strtolower($category->name);
            $names[] = $name;   
        }   */
        
        // добавляем процентов 30 single form тега
        if ($tag && $tag->single_form) {
            $n = count($names) * 0.3;
            $n = (int)$n;
            if ($n < 1) {
                $n = 1;    
            } 
            
            for ($i = 0; $i < $n; $i++) {
                $names[] = $tag->single_form;            
            } 
        }
        
        // если вообще ничего нет, то возвращаем name товара
        if (!count($names)) {
            return $this->name;   
        }  
        
        // рандомно
        $seed = $this->id;
        if ($category) {
            $seed += $category->id;    
        }
        if ($tag) {
            $seed += $tag->id;   
        }
		$region = ORM::factory('region')->get_current();
		if ($region) {
			$seed += $region->id;
		}
        mt_srand($seed);              
        $n = mt_rand(0, count($names)-1);
        $name = $names[$n];
        
        // разобраться с возможным дублем бренда (по наличию заглавной в названии)
        if (mb_strtolower($name) === $name) {
            $name .= ' '.$this->brand;
        }
        return $name;
    }
    
    public function get_image()
    {
        if (!$this->is_image) {
            return $this->picture;
        }
        $path = 'http://img.cashbackdoc.com/products/';
        $path = $path.sprintf('%02x/', $this->id % 0xff);
        $path = $path.sprintf('%02x/', $this->id % 0xcf);
        $path = $path.sprintf('%02x/', $this->id % 0x8f);
        $path = $path.sprintf('%02x/', $this->id % 0x4f);
        $path = $path.sprintf('%d/', $this->id);

        $filename = $path.Model_Main::translit($this->name).'-small.jpg';
        return $filename;
    }
    
    public function get_images($product_data)
    {
		if (!$product_data['images']) {
			return array();
		}
        $_images = explode('||', $product_data['images']);
		$images = array();
		foreach ($_images as $n => $image) {
            $images[$n]['big'] = $image;
            $images[$n]['small'] = $image;    
        }
		return $images;
		
        if (!$this->is_image) {
            if ($product_data['images']) {
                return $images;   
            }
            return array();
        }
        $path = 'http://img.cashbackdoc.com/products/';
        $path = $path.sprintf('%02x/', $this->id % 0xff);
        $path = $path.sprintf('%02x/', $this->id % 0xcf);
        $path = $path.sprintf('%02x/', $this->id % 0x8f);
        $path = $path.sprintf('%02x/', $this->id % 0x4f);
        $path = $path.sprintf('%d/', $this->id);

        $images = array();
        
        foreach ($_images as $n => $image) {
            $images[$n]['big'] = $path.Model_Main::translit($this->name).'-'.($n+1).'.jpg';
            $images[$n]['small'] = $path.Model_Main::translit($this->name).'-'.($n+1).'-small.jpg';    
        }
        
        /*$handler = opendir($path);
        while (false !== ($entry = readdir($handler))) {
            if ($entry != "." && $entry != ".." && $entry != $path.Model_Main::translit($this->name).'-small.jpg') {
                $images[] = $entry;
            }
        }
        closedir($handler);*/
        
        return $images;
    }
    
    public function get_url($coupon = null)
    {
        if (in_array($this->shop_id, array(4102))) {
            $url  = $this->_get_clean_url();
            $rand = mt_rand(0, 100);     
            if ($rand < 50) {       // admitad
                $pattern = 'http://ad.admitad.com/goto/1d9ed345ddea57d2938cdc28f2033d/?ulp=%url%&subid=%subaccount%';       
            } else {                // actionpay
                $pattern = 'http://n.actionpay.ru/click/52446a13fc3f5b858c000031/54232/%subaccount%/url=%url%';  			
            }
                  
            $subid = Model_Main::get_subid($this, $coupon);
            return str_replace(array('%url%', '%subaccount%'), array($url, $subid), $pattern);
        }   
           
        $url   = $this->url; 
        $subid = Model_Main::get_subid($this, $coupon);     
        if (strstr($url, 'actionpay.ru') !== false) {
            $url = str_replace('/subaccount/', '/'.$subid.'/', $url);
        }
        if (strstr($url, 'admitad.com') !== false) {
            $url = str_replace('/?ulp=', '/subid/'.$subid.'/?ulp=', $url);
        }
        return $url; 
    }
    
    /**
    * Возвращает конечную цену, ссылку и список скидок на данный товар
    * 
    * @param mixed $coupon
    * @param mixed $shop
    */
    public function get_price($coupon = null, $shop = null)
    {
        $result = array(
            'price'      => $this->price,
            'oldprice'   => null,
            'percentage' => null,
            'url'        => Helper_Index::go_product_url($this),
            'history'    => array(),
        );
        if ($this->oldprice != $this->price) {
            $result['oldprice'] = $this->oldprice;  
        }
        $newdiscount = 0;  
        
        // узнаем, есть ли у магазина скидка
        if ($result['oldprice']) {
            $percentage = (100 - round(100*$result['price']/$result['oldprice'], 2));
            $result['history']['discount'] = str_replace('.', ',', $percentage);    
        }
        
        // если есть купон, вычисляем цену
        if ($coupon) {
            $newprice      = $coupon->get_product_discount_price($this);
            $newdiscount   = $result['price'] - $newprice;  
            $percentage    = (100 - round(100*$newprice/$result['price'], 2));
            $result['history']['coupon'] = str_replace('.', ',', $percentage); 
            $result['url'] = Helper_Index::go_coupon_url($coupon, $this);  
        }
        
        // если у магазина есть кэшбэк и юзер залогинен, то вычисляем цену 
        $user = Model_Auth::instance()->get_user();
        if ($user && $shop && $shop->cashback_payment_size) {
            // если нет "-", то все просто
            $value = $shop->cashback_payment_size;
            
            // если есть и это ламода, то проверяем купон
            // если есть и не ламода, то берем большую скидку
            if (strstr($shop->cashback_payment_size, '-') !== false) {
                list($mindiscount, $maxdiscount) = explode('-', $shop->cashback_payment_size);
                $value = $maxdiscount;
                if ($shop->id == 1001) {
                    if ($coupon) {
                        $value = $mindiscount;    
                    }        
                }   
            }
            
			if ($shop->percentage) {
				$newdiscount = $newdiscount + round($result['price']*$value/100, 2);
				$percentage  = $value;
			} else {
				$newdiscount = $newdiscount + $value;
				$percentage  = round($value*100/$result['price'], 2);
				if ($newdiscount > $result['price']) {
					$newdiscount = $result['price'];
					$percentage  = 100;
				}
			}
			
			$result['history']['cashback'] = str_replace('.', ',', $percentage); 
        }                
        
        $newprice = $result['price'] - $newdiscount; 
        if ($newprice != $result['price']) {
            if (!$result['oldprice']) {
                $result['oldprice'] = $result['price'];    
            }   
            $result['price'] = $newprice;
        } 
        if ($result['oldprice'] && $result['oldprice'] != $result['price']) {
            $result['percentage'] = 100 - round($result['price']*100/$result['oldprice'], 2);
            $result['percentage'] = str_replace('.', ',', $result['percentage']);    
        }
        return $result;
    }
    
    protected function _get_clean_url()
    {
        $url = $this->url;
        if (strstr($url, 'admitad.com') !== false) {
            $delimeter = '?ulp=';
            $pos = strpos($url, $delimeter) + strlen($delimeter);
            $url = substr($url, $pos);
            $url = str_replace(array('%3A', '%2F'), array(':', '/'), $url);
        }
        return $url;
    }
    
    protected function _get_products_query()
    {
        return ORM::factory('product')->where('is_available', '=', 1);
    }
    
    public function process_params()
    {
        /*
        515     Quelle          цвет
        1001    Lamoda          цвет, материал, сезон
        1186    Proskater       цвет
        1326    TOPBRANDS       цвет, материал
        1477    ShopTime        -
        1757    BUTIK           цвет
        2775    MEXX            -
        2777    TomTailor       -
        3761    SHOWROOMS       материал
        4102    Wildberries     цвет, материал (состав), сезон, стиль
        */
        
        $_params = $this->extract_specs();
        $params  = array();
        if ($_params) {
            foreach ($_params as $name => $value) {
                $value = mb_strtolower(trim($value));
                $name  = mb_strtolower($name);
                $params[$name] = $value;                         
            }
        }
        
        $color = array(); $_color = null;
        $composition = array(); $_composition = null;
        $season = array(); $_season = null;
        
        if ($this->shop_id == 515) {       
            if (isset($params['цвет'])) {
                $_color = $params['цвет'];
            }                       
        } else if ($this->shop_id == 1001) {
            if (isset($params['цвет'])) {
                $_color = $params['цвет'];
            }
            if (isset($params['внешний материал'])) {
                $_composition = $params['внешний материал'];
            }
            if (isset($params['сезонность'])) {
                $_season = $params['сезонность'];
                if ($_season == 'мульти') {
                    $season[] = Model_Season::MULTI_SEASON;
                }
            }           
        } else if ($this->shop_id == 1186) {
            if (isset($params['цвет'])) {
                $_color = $params['цвет'];
            }     
        } else if ($this->shop_id == 1326) {
            if (isset($params['цвет'])) {
                $_color = $params['цвет'];
            } 
            if (isset($params['материал'])) {
                $_composition = $params['материал'];
            }     
        } else if ($this->shop_id == 1477) {
                
        } else if ($this->shop_id == 1757) {
            $_color = null;
            if (isset($params['цвет'])) {
                $_color = $params['цвет'];
            }     
        } else if ($this->shop_id == 2775) {
                
        } else if ($this->shop_id == 2777) {
                
        } else if ($this->shop_id == 3761) {
            if (isset($params['материал'])) {
                $_composition = $params['материал'];
            }        
        } else if ($this->shop_id == 4102) {
            if (isset($params['цвет'])) {
                $_color = $params['цвет'];
            }
            if (isset($params['состав'])) {
                $_composition = $params['состав'];
            } 
            if (isset($params['сезон'])) {
                $_season = $params['сезон'];
            }   
        }
        
        if (!$color && $_color) {
            $words = explode(',', $_color);
            foreach ($words as $word) {
                foreach (Model_Color::$color_options as $id => $item) {
                    if (strstr($word, $item['name']) !== false) {
                        $color[] = $id; 
                    }    
                }   
            }    
        }
        
        if (!$composition && $_composition) {
            $words = explode(',', $_composition);
            foreach ($words as $word) {
                foreach (Model_Composition::$composition_options as $id => $item) {
                    if (strstr($word, $item['name']) !== false) {
                        $composition[] = $id;    
                    }    
                }
            }    
        }
        
        if (!$season && $_season) {
            $words = explode(',', $_season);
            foreach ($words as $word) {
                foreach (Model_Season::$season_options as $id => $item) {
                    if (strstr($word, $item['name']) !== false) {
                        $season[] = $id;    
                    }    
                } 
            }   
        }
        
        if (isset($color[0])) {
            $this->color_id = $color[0]; 
        }
        
        if (isset($composition[0])) {
            $this->composition_id = $composition[0];
        }
        
        if (isset($season[0])) {
            $this->season_id = $season[0];
        }
        
        /*foreach ($color as $color_id) {
            try { 
                DB::insert('product_colors', array('product_id', 'color_id'))
                    ->values(array($this->id, $color_id))
                    ->execute();
            } catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {
                    continue;
                } else {
                    die($e->getMessage());
                }
            }   
        }
        
        foreach ($composition as $composition_id) {
            try { 
                DB::insert('product_compositions', array('product_id', 'composition_id'))
                    ->values(array($this->id, $composition_id))
                    ->execute();
            } catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {
                    continue;
                } else {
                    die($e->getMessage());
                }
            }   
        }
        
        foreach ($season as $season_id) {
            try { 
                DB::insert('product_seasons', array('product_id', 'season_id'))
                    ->values(array($this->id, $season_id))
                    ->execute();
            } catch (Database_Exception $e) {
                if (strstr($e->getMessage(), 'Duplicate entry') !== false) {
                    continue;
                } else {
                    die($e->getMessage());
                }
            }   
        }  */
        
        $this->is_processed = 1;
        $this->save();
    }
    
    public function search($query, $page = 1, $category = null, $is_test = false)
    {
        $query = self::get_clean_search_query($query);
        $query = str_replace(
            array(' в ', 'для полных', 'для детей', 'для женщин', 'шапок', 'норковую', 'штаны'),
            array(' ', 'больших размеров', 'детские', 'женские', 'шапки', 'норка', 'брюки'),
            $query
        );
        
        $stop_words = array(
            /*'дешев', 'дорог', 'доставк', 'заказ', 'магазин', 'интернет', 'купить', 'куплю', 'москв', 'продаж', 'цен', 'скидк', 'где', 'можно',
            'спб', 'розниц', 'наложенны', 'платеж', 'через', 'хочу', 'форум', 'оригинал', 'бренд', 'онлайн', 'какие', 'каталог', /*'2012', '2013', '2014', */
            /*'лучш', 'фото', 'новый', 'фирм', 'элитн', 'настоящ', 'официальн', 'сайт', 'классный', 'импортный', */
            
            /*'красноярск', 'екатеринбург', 'челябинск', 'ярославл', 'стамбул', 'тюмен', 'питер', 'омск', 'киров', 'тул', 'саратов', 'харьков',
            'нижн', 'новгород', 'новосибирск', 'перм', 'воронеж', 'ростов', /*'уф',*/ /*'краснодар', 'санкт', 'петербург', 'самар', 'казан', 'иркутск',
            'хабаровск', 'киров', 'ижевск', 'барнаул', 'кемеров', 'луганск', 'твер', 'липецк', 'волгоград', 'пенз', 'костром', 'ульяновск',
            'владимир', 'николаев', 'витебск', 'курск', 'тольятти', 'кривой рог', 'кривом рогу', 'сургут', 'чит', 'белгород', 'иваново', 'брянск',
            'курган', 'смоленск', 'тамбов', 'могилев', 'калининград', 'хмельницк', 'владивосток', 'саранск', */
        );
        
        $repalces = array(
			// Страны
            'итальянск' => 'италия',
            'российск'  => 'россия',
            'китайск'   => 'китай',
            'канадск'   => 'канада',
            'немецк'    => 'германия',
            'японск'    => 'япония',
            'шведск'    => 'швеция',
            'польск'    => 'польша',
            'финск'     => 'финляндия',
            'турецк'    => 'турция',
			'индийск'	=> 'индия',
			
			// Состав
			'хлопков' 		=> 'хлопок',
			'полиэстеров' 	=> 'полиэстер',
			'кожан' 		=> 'кожа',
			'нейлонов' 		=> 'нейлон',
			'пластиков' 	=> 'пластик',
			'шерстян' 		=> 'шерсть',
			'текстильн' 	=> 'текстиль',
			'акрилов' 		=> 'акрил',
			'металлич' 		=> 'металл',
			'лайкров' 		=> 'лайкра',
			'льнян' 		=> 'лен',
			'полиуретанов' 	=> 'полиуретан',
			'шелков' 		=> 'шелк',
			'велюров' 		=> 'велюр',
			'замшев' 		=> 'замша',
			'полиакрилов' 	=> 'полиакрил',
			'фарфоров' 		=> 'фарфор',
			'нубуков' 		=> 'нубук',
			'стеклян' 		=> 'стекло',
			'ангоров' 		=> 'ангора',
			'кашемиров' 	=> 'кашемир',
			'резинов' 		=> 'резина',
			'стальн' 		=> 'сталь',
			'бумажн' 		=> 'бумага',
			'нубуков' 		=> 'нубук',
			'деревян' 		=> 'дерево',
			
			// Сезон
			'летн' 			=> 'лето',
			'демисезонн' 	=> 'демисезон',
			'зимн' 			=> 'зима',
        );
		
		$prepositions = array(
			'из', 'с', 'на',
		);
        
        $words       = explode(' ', $query);
        $clean_query = array();
        foreach ($words as $word) {
            $word  = trim($word);
            $found = false;
            foreach ($stop_words as $stop_word) {
                if (strstr($word, $stop_word) !== false) {
                    $found = true;
                    break;
                }    
            } 
			foreach ($prepositions as $preposition) {
				if ($word == $preposition) {
                    $found = true;
                    break;
                } 
			}
            if (!$found) {
                $found = false;
                foreach ($repalces as $first => $second) {
                    if (strstr($word, $first) !== false) {
                        $clean_query[] = $second;
                        $found = true;
                        break;
                    }    
                }
                if (!$found) {
                    $clean_query[] = $word;   
                }
            }
        }
        $clean_query = implode(' ', $clean_query);
        
        $limit  = self::get_products_per_page();
        $offset = 0;
        if ($page) {
            $limit = self::get_products_per_page();
            $offset = ($page - 1) * $limit;   
        }
        
        // создаем инстанц клиента
        $cl = new Library_SphinxClient();
         
        // настройки
        $cl->SetServer("localhost", 9312);
        //$cl->SetServer("46.28.69.161", 9312); 
        $cl->SetConnectTimeout(5);
        if ($is_test) {
            $cl->SetLimits(0, 100000, 100000);    
        } else {
            $cl->SetLimits($offset, $limit, 1000);   
        }
        $cl->SetMatchMode(SPH_MATCH_EXTENDED);
        $cl->SetArrayResult(true);
        $cl->SetFieldWeights(array (
            'product_name'   => 100,
            'brand_synonyms' => 70,
            'category_name'  => 70,
            'description'    => 70,
            'product_clean_params'     => 70,
            'product_invisible_params' => 20,
            'brand_name'     => 10,
        )); 
        //$cl->SetSortMode(SPH_SORT_EXPR, 'product_sort DESC, product_price ASC');
        //$cl->SetSortMode(SPH_SORT_ATTR_DESC, 'product_sort');
        
        //$cl->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
        //$cl->SetMatchMode(SPH_MATCH_ANY);
        
        if ($category) {
            $category_id = $category;
            if ($category instanceof Model_Category) {
                $category_id = $category->id;    
            }
			$category_filter = array($category_id);
			if (is_array($category)) {
				$category_filter = $category;
			}
            $cl->SetFilter('product_category_id', $category_filter);
        }
        
        $result = $cl->Query($clean_query);
        
        $products = array();
        $count    = 0;
        if ($result) {
            if ($is_test) {
                $_result = array(
                    'products' => array(),
                    'count'    => 0,
                );
                if ($result['total']) {
                    foreach ($result['matches'] as $match) {
                        $_result['products'][] = array(
                            'id' => $match['id'],
                            'weight' => $match['weight'],
                        );
                    } 
                    $_result['count'] = $result['total']; 
                }
                return $_result;    
            }
            if (isset($result['matches'])) {
                $ids = array();
                $n = 1;
                foreach ($result['matches'] as $match) {
                    $ids[$match['id']] = $n;
                    $n++;   
                }
                $_products = ORM::factory('product')
                                ->where('id', 'IN', array_keys($ids))
                                ->where('is_available', '=', 1)
                                //->order_by('price', 'ASC')
                                ->find_all()
                                ->as_array();
                foreach ($_products as $product) {
                    $products[$ids[$product->id]] = $product;     
                }
                ksort($products);
            } 
            if (isset($result['total'])) {
                $count = $result['total'];
            }   
        }
        
        return array(
            'products' => $products,
            'count'    => $count,
        );
    }
    
    public static function get_clean_params($params)
    {
        $clean_params = array();
        if ($params) {
            foreach (json_decode($params, true) as $name => $value) {
                $value = mb_strtolower(trim($value));
                $name  = mb_strtolower($name);
                
                $clean_params[] = $name.' '.$value;                         
            }
        } 
        $clean_params = implode('; ', $clean_params);
        if ($clean_params) {
            return $clean_params;
        }   
        return null;
    }
    
    public static function get_clean_search_query($query)
    {
        return str_replace(array('+', 'ё', '"'), array('', 'е', ''), $query);
    }
    
    /**
    * Семантический анализатор категории данного товара
    * 
    * @param mixed $categories
    */
    public function semantic_analyze_category($categories)
    {
        /*function get_category_breadcrumbs($cat_id, &$cats)
        {
            $text = array();
            $cat = $cats[$cat_id];
            while ($cat['parent_id'] != 0) {
                $cat = $cats[$cat['parent_id']];
                $text[] = $cat['name'];
            }
            return implode(' ', $text);
        }  */
        
        $category_lenght_ratio = 15;
        $min_relevance         = 5;
        
        $stop_words = array(
           'что', 'как', 'все', 'она', 'так', 'его', 'только', 'мне', 'было', 'вот',
           'меня', 'еще', 'нет', 'ему', 'теперь', 'когда', 'даже', 'вдруг', 'если',
           'уже', 'или', 'быть', 'был', 'него', 'вас', 'нибудь', 'опять', 'вам', 'ведь',
           'там', 'потом', 'себя', 'может', 'они', 'тут', 'где', 'есть', 'надо', 'ней',
           'для', 'тебя', 'чем', 'была', 'сам', 'чтоб', 'без', 'будто', 'чего', 'раз',
           'тоже', 'себе', 'под', 'будет', 'тогда', 'кто', 'этот', 'того', 'потому',
           'этого', 'какой', 'ним', 'этом', 'один', 'почти', 'мой', 'тем', 'чтобы',
           'нее', 'были', 'куда', 'зачем', 'всех', 'можно', 'при', 'два', 'другой',
           'хоть', 'после', 'над', 'больше', 'тот', 'через', 'эти', 'нас', 'про', 'них',
           'какая', 'много', 'разве', 'три', 'эту', 'моя', 'свою', 'этой', 'перед',
           'чуть', 'том', 'такой', 'более', 'всю'
        );
        
        $product_data = $this->get_product_data();
        
        $data = array(
            'name'     => array(
                'value'  => mb_strtolower(Model_Main::get_clean_name($this->name)),
                'weight' => 2,
            ),
            'category' => array(
                'value'  => mb_strtolower(Model_Main::get_clean_name($product_data['invisible_params'])),
                'weight' => 0.5,
            ),
        );
        // название товара и иерархию категорий разбиваем на слова
        // лемматизация слов
        $product_words = array();
        foreach ($data as $part) {
            $words  = explode(' ', $part['value']);
            $weight = $part['weight']; 
            foreach ($words as $word) {
                if ($word) {
                    if (in_array($word, $stop_words)) {
                        continue;
                    }
                    $product_words[] = array(
                        'value'  => Model_Stemmer::stem(trim($word)),
                        'weight' => $weight,
                    );    
                }
            }   
        }
        
        // цикл по категориям
        $relevance_list = array();
        foreach ($categories as $category_id => $category_item) {
            $relevance = 0;
            // попарно сравниваем леммы слов и высчитываем релевантность
            /*foreach ($product_words as $product_word_item) {
                $count = substr_count($category_item['text'], $product_word_item['value']);
                $relevance += $count*$product_word_item['weight'];  
            } */  
            foreach ($category_item['words'] as $category_word_item) {
                foreach ($product_words as $product_word_item) {
                    
                    if ($product_word_item['value'] == $category_word_item['value']) {
                        $relevance += $product_word_item['weight']*$category_word_item['weight'];    
                    }    
                }    
            }   
            $relevance_list['cat-'.$category_id] = $relevance;
        }
        arsort($relevance_list);
        $_relevance_list = array_slice($relevance_list, 0, 10);
        $relevance_list = array();      // какой-то баг с arsort и целочисленными ключами
        foreach ($_relevance_list as $key => $value) {
            list($tmp, $category_id) = explode('-', $key);
            $name = $categories[$category_id]['object']->nominative_form;
            // релевантность прямопропорциональна кол-ву вхождений и обратнопр. длине названия
            $relevance = $value + $value*$category_lenght_ratio/mb_strlen($name);
            if ($relevance > $min_relevance) {
                $relevance_list[$category_id] = $relevance; //.' - '.$name;
            }
        }
        arsort($relevance_list);
        
        $category_id = 0;
        if (count($relevance_list)) {
            $tmp_array = array_slice(array_keys($relevance_list), 0, 1);
            $category_id = $tmp_array[0];    
        }
        
        //print_r($relevance_list);
        //echo $category_id;
        
        if ($category_id) {
            $this->category_id = $category_id;   
        }
        $this->is_categorized = 1;
        $this->save();
        
        
        /*echo $this->name.'<br />';
        echo $product_data['invisible_params'];
        echo '<pre>';
        print_r($relevance_list);
        echo '<br />';*/    
            
    }
    
    public function get_rating()
    {
        $one   = $this->count_one_stars;
        $two   = $this->count_two_stars;
        $three = $this->count_three_stars;
        $four  = $this->count_four_stars;
        $five  = $this->count_five_stars;
        
        $count = $one + $two + $three + $four + $five;
        $rating = 0;
        if ($count) {
            $rating = ($one + 2*$two + 3*$three + 4*$four + 5*$five) / $count;
        } 
        return array(
            'count'  => $count,
            'rating' => round($rating, 2),
        ); 
    }
    
    public function change_count_reviews()
    {
        //$column_name = ($entity ? $entity . '_' : '') . 'count_reviews';
        $column_name = 'count_reviews';
        $this->set($column_name, $this->__get($column_name) + 1); 
        $this->save(); 
    }
    
    public function change_count_stars($rating)
    {        
        if (!$rating) {
            return false;
        }   
        $stars = array(
            1 => 'one',
            2 => 'two',
            3 => 'three',
            4 => 'four',
            5 => 'five',
        );
        if (!array_key_exists($rating, $stars)) {
            throw new Model_Exception('Неверный рейтинг');
        }
        $star = $stars[$rating];
        //$column_name = ($entity ? $entity . '_' : '') . 'count_' . $star . '_stars';
        $column_name = 'count_' . $star . '_stars';
        $this->set($column_name, $this->__get($column_name) + 1);
        $this->save();
    }
}
